﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using ColinHan.BlamBlam.Client.Entities;
using ColinHan.Windows.Foundation.MVVM;

namespace ColinHan.BlamBlam.Client.ViewModels
{
    class CurrentTaskViewModel : ViewModelBase
    {
        public CurrentTaskViewModel()
        {
            Pause = new RelayCommand(OnPause, CanPause);
            Resume = new RelayCommand(OnResume, CanResume);
            Complete = new RelayCommand(OnComplete, CanComplete);

            _timer = new DispatcherTimer();
            _timer.Interval = TickTime; // 1 second.
            _timer.Tick += new EventHandler(Timer_Tick);
        }

        #region Properties & Fields

        private static readonly TimeSpan RunningTime = new TimeSpan(0, 25, 0);
        private static readonly TimeSpan ShortRestingTime = new TimeSpan(0, 5, 0);
        private static readonly TimeSpan LongRestingTime = new TimeSpan(0, 20, 0);
        private static readonly TimeSpan TickTime = new TimeSpan(0, 0, 1);

        private Task _currentTask;
        public Task CurrentTask
        {
            get { return _currentTask; }
            set
            {
                if (_currentTask != value)
                {
                    _currentTask = value;
                    this.OnPropertyChanged("CurrentTask");
                }
            }
        }

        public readonly RelayCommand Pause;
        public readonly RelayCommand Resume;
        public readonly RelayCommand Complete;

        private CurrentTaskStatus _status;
        public CurrentTaskStatus Status
        {
            get { return _status; }
            private set
            {
                if (_status != value)
                {
                    _status = value;
                    this.OnPropertyChanged("Status");
                }
            }
        }
        public TimeSpan LeftTimeOfCurrentRound
        {
            get { return ElapsedOfCurrentRound - DurationOfCurrentRound; }
        }
        public TimeSpan ElapsedOfCurrentRound { get; private set; }
        public TimeSpan DurationOfCurrentRound { get; private set; }
        private Record CurrentRecord { get; set; }

        public int Round
        {
            get { return _round; }
            set
            {
                if (_round != value)
                {
                    _round = value;
                    this.OnPropertyChanged("Round");
                }
            }
        }

        private DispatcherTimer _timer;
        private int _round;

        #endregion

        #region Methods
        private void OnPause(object param)
        {
            Debug.Assert(CanPause(param));

            Status = CurrentTaskStatus.Pause;
        }
        private bool CanPause(object param)
        {
            return this.Status == CurrentTaskStatus.Running;
        }
        private void OnResume(object param)
        {
            Debug.Assert(CanResume(param));

            if (this.Status == CurrentTaskStatus.Waiting)
            {
                StartNewRecord();
            }
            Status = CurrentTaskStatus.Running;
        }
        private bool CanResume(object param)
        {
            return this.Status == CurrentTaskStatus.Pause ||
                   this.Status == CurrentTaskStatus.Waiting;
        }

        private void OnComplete(object param)
        {
            this.CurrentTask.State = TaskState.Completed;
            var handler = this.Completed;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
        private bool CanComplete(object param)
        {
            return this.CurrentTask != null;
        }

        private void StartNewRecord()
        {
            this.CurrentRecord = new Record(this.CurrentTask);
            this.CurrentRecord.StartTime = DateTime.Now;
            this.CurrentTask.Records.Add(this.CurrentRecord);
        }
        private void StopCurrentRecord()
        {
            this.CurrentRecord.EndTime = DateTime.Now;
            this.CurrentRecord = null;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            Debug.Assert(this.Status == CurrentTaskStatus.Running ||
                         this.Status == CurrentTaskStatus.ShortResting);

            this.ElapsedOfCurrentRound += TickTime;
            if (this.ElapsedOfCurrentRound == TimeSpan.Zero)
            {
                if (this.Status == CurrentTaskStatus.Running)
                {
                    this.StopCurrentRecord();
                    if (_round == 3)
                    {
                        this.Status = CurrentTaskStatus.LongResting;
                        this.DurationOfCurrentRound = LongRestingTime;
                    }
                    else
                    {
                        this.Status = CurrentTaskStatus.ShortResting;
                        this.DurationOfCurrentRound = ShortRestingTime;
                    }
                    this.ElapsedOfCurrentRound = TimeSpan.Zero;
                }
                else if (this.Status == CurrentTaskStatus.ShortResting ||
                    this.Status == CurrentTaskStatus.LongResting)
                {
                    _round++;
                    if (_round >= 4)
                    {
                        _round = 0;
                    }
                    this.Status = CurrentTaskStatus.Waiting;
                    this.DurationOfCurrentRound = RunningTime;
                    this.ElapsedOfCurrentRound = TimeSpan.Zero;
                    this._timer.Stop();
                }
            }

            this.OnTimeOfCurrentRoundChanged();
        }
        private void OnTimeOfCurrentRoundChanged()
        {
            this.OnPropertyChanged("LeftTimeOfCurrentRound");
            this.OnPropertyChanged("ElapsedOfCurrentRound");
            this.OnPropertyChanged("DurationOfCurrentRound");
        }

        #endregion

        #region Events
        public event EventHandler Completed;
        #endregion
    }

    public enum CurrentTaskStatus
    {
        None,
        Running,
        Pause,
        ShortResting,
        LongResting,
        Waiting,
    }
}
